﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace Common.DBFHelper
{
    public abstract  class DBFRecordBase
    {
        protected static System.Text.Encoding encoding = Encoding.GetEncoding("GB2312");

        /// <summary>
        /// 从字节数组中读取DBF记录
        /// </summary>
        /// <param name="buffer">字节数组</param>
        /// <param name="offset">偏移</param>
        /// <returns></returns>
        public abstract DBFRecordBase ReadRecordFromBuffer(byte[] buffer, int offset, Dictionary<string, DbfColumn> columnDic);

        //protected Int32 ReadInt32(byte[] bytes, int offset = 0)
        //{
        //    // 参数检查
        //    if (null == bytes)
        //    {
        //        // 参数为空
        //        throw new ArgumentNullException("bytes");
        //    }
        //    if (offset + 4 > bytes.Length)
        //    {
        //        // 如果参数buf的长度不为4，抛出参数异常
        //        throw new ArgumentException("函数Byte2Int32(byte[])的参数必须是长度为4的有效byte数组", "buf");
        //    }

        //    // byte[] 解码成 int
        //    return (int)((((bytes[offset] & 0xff) | (bytes[offset + 1] << 8)) | (bytes[offset + 2] << 0x10)) | (bytes[offset + 3] << 0x18));
        //}

        //protected Int64 ReadInt64(byte[] bytes, int offset = 0)
        //{
        //    // 参数检查
        //    if (null == bytes)
        //    {
        //        // 参数为空
        //        throw new ArgumentNullException("bytes");
        //    }
        //    if (offset + 8 > bytes.Length)
        //    {
        //        // 如果参数buf的长度不为4，抛出参数异常
        //        throw new ArgumentException("函数Byte2Int64(byte[])的参数必须是长度为8的有效byte数组", "buf");
        //    }

        //    // byte[] 解码成 long
        //    uint num1 = (uint)(((bytes[offset] | (bytes[offset + 1] << 8)) | (bytes[offset + 2] << 0x10)) | (bytes[offset + 3] << 0x18));
        //    uint num2 = (uint)(((bytes[offset + 4] | (bytes[offset + 5] << 8)) | (bytes[offset + 6] << 0x10)) | (bytes[offset + 7] << 0x18));

        //    return (long)(((ulong)num2 << 0x20) | num1);
        //}

        //protected DateTime ReadDate(byte[] bytes, int offset = 0)
        //{
        //    // 参数检查
        //    if (null == bytes)
        //    {
        //        // 参数为空
        //        throw new ArgumentNullException("bytes");
        //    }
        //    if (offset + 8 > bytes.Length)
        //    {
        //        // 如果参数buf的长度不为8，抛出参数异常
        //        throw new ArgumentException("函数Byte2DateTime(byte[])的参数必须是长度为8的有效byte数组", "buf");
        //    }


        //    string str1 = encoding.GetString(bytes);
        //    str1 = str1.Trim();
        //    if (str1.Length < 8)
        //    {
        //        return new DateTime();
        //    }
        //    int year = int.Parse(str1.Substring(0, 4));
        //    int month = int.Parse(str1.Substring(4, 2));
        //    int day = int.Parse(str1.Substring(6, 2));
        //    return new DateTime(year, month, day);

        //}

        //protected DateTime ReadDateTime(byte[] bytes, int offset = 0)
        //{
        //    // 参数检查
        //    if (null == bytes)
        //    {
        //        // 参数为空
        //        throw new ArgumentNullException("bytes");
        //    }
        //    if (offset + 8 > bytes.Length)
        //    {
        //        // 如果参数buf的长度不为8，抛出参数异常
        //        throw new ArgumentException("函数Byte2DateTime(byte[])的参数必须是长度为8的有效byte数组", "buf");
        //    }

        //    try
        //    {
    
        //        // 获取天数
        //        int days = ReadInt32(bytes,offset);
        //        int milliSeconds = ReadInt32(bytes,offset +4);
        //        // 在最小日期时间的基础上添加刚获取的天数和毫秒数，得到日期字段数值
        //        DateTime minDateTime = DateTime.MinValue;
        //        minDateTime = minDateTime.AddDays(days - 1721426);
        //        minDateTime = minDateTime.AddMilliseconds((double)milliSeconds);

        //        return minDateTime;
        //    }
        //    catch
        //    {
        //        return new DateTime();
        //    }
        //}

        //protected string ReadString(byte[] bytes, int offset, int length, bool trim)
        //{
        //    try
        //    {
        //        string str = encoding.GetString(bytes, offset, length);
        //        if (!string.IsNullOrEmpty(str) && trim)
        //        {
        //            str = str.Trim('\0').Trim();
        //            if (string.IsNullOrEmpty(str))
        //                str = null;
        //        }
        //        return str;
        //    }
        //    catch
        //    {
        //        return null;
        //    }
        
        //}







        /// <summary>
        /// 从缓冲区中读取指定字段的数据，并转换成字符串
        /// </summary>
        /// <param name="buffer">数据缓冲区</param>
        /// <param name="recordOffset">记录起始位置在缓冲区中的偏移量</param>
        /// <param name="fieldOffset">字段在记录内的偏移量</param>
        /// <param name="fieldLength">字段长度</param>
        /// <param name="trim"></param>
        /// <returns>如果读取成功，则返回字符串信息，否则返回string.Empty</returns>
        protected static string ReadFieldString(byte[] buffer, int recordOffset, int fieldOffset, int fieldLength, bool trim = false)
        {
            try
            {
                string str = encoding.GetString(buffer, recordOffset + fieldOffset, fieldLength);
                if (!string.IsNullOrEmpty(str) && trim)
                {
                    str = str.Trim('\0').Trim();
                    if (string.IsNullOrEmpty(str))
                        str = null;
                }
                return str;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 从缓冲区中读取指定字段的数据，并转换成double型数值
        /// </summary>
        /// <param name="buffer">数据缓冲区</param>
        /// <param name="recordOffset">记录起始位置在缓冲区中的偏移量</param>
        /// <param name="fieldOffset">字段在记录内的偏移量</param>
        /// <param name="fieldLength">字段长度</param>
        /// <returns>如果读取成功，则返回double型数值，否则返回0.0</returns>
        protected static double ReadDoubleField(byte[] buffer, int recordOffset, int fieldOffset, int fieldLength)
        {
            // 读取字段数据
            string str = ReadFieldString(buffer, recordOffset, fieldOffset, fieldLength);
            if (string.IsNullOrEmpty(str))
                return 0.0;

            // 转换成double型数值
            double rtn;
            if (double.TryParse(str, out rtn))
                return rtn;
            else
                return 0.0;
        }

        /// <summary>
        /// 从缓冲区中读取指定字段的数据，并转换成int型数值
        /// </summary>
        /// <param name="buffer">数据缓冲区</param>
        /// <param name="recordOffset">记录起始位置在缓冲区中的偏移量</param>
        /// <param name="fieldOffset">字段在记录内的偏移量</param>
        /// <param name="fieldLength">字段长度</param>
        /// <returns>如果读取成功，则返回int型数值，否则返回0</returns>
        protected static int ReadIntField(byte[] buffer, int recordOffset, int fieldOffset, int fieldLength)
        {
            // 读取字段数据
            string str = ReadFieldString(buffer, recordOffset, fieldOffset, fieldLength);
            if (string.IsNullOrEmpty(str))
                return 0;

            // 转换成int型数值
            int rtn;
            if (int.TryParse(str, out rtn))
                return rtn;
            else
                return 0;
        }

        /// <summary>
        /// 从缓冲区中读取指定字段的数据，并转换成Int64型数值
        /// </summary>
        /// <param name="buffer">数据缓冲区</param>
        /// <param name="recordOffset">记录起始位置在缓冲区中的偏移量</param>
        /// <param name="fieldOffset">字段在记录内的偏移量</param>
        /// <param name="fieldLength">字段长度</param>
        /// <returns>如果读取成功，则返回int型数值，否则返回0</returns>
        protected static long ReadInt64Field(byte[] buffer, int recordOffset, int fieldOffset, int fieldLength)
        {
            // 读取字段数据
            string str = ReadFieldString(buffer, recordOffset, fieldOffset, fieldLength);
            if (string.IsNullOrEmpty(str))
                return 0;

            long rtn;
            if (long.TryParse(str, out rtn))
                return rtn;
            else
                return 0;
        }

        /// <summary>
        /// 从缓冲区中读取指定字段的数据，并转换成字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="recordOffset"></param>
        /// <param name="fieldOffset"></param>
        /// <param name="fieldLength"></param>
        /// <returns></returns>
        protected static string ReadStringField(byte[] buffer, int recordOffset, int fieldOffset, int fieldLength)
        {
            return ReadFieldString(buffer, recordOffset, fieldOffset, fieldLength, true);
        }
  
    }

    public abstract class DBFRecordBase<T> : DBFRecordBase
        where T : DBFRecordBase
    {
        private static T seed;
        delegate T ObjectActivator();
        static ObjectActivator dlg;
        static DBFRecordBase()
        {
            NewExpression newExp = Expression.New(typeof(T));
            LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp);
            dlg = (ObjectActivator)lambda.Compile();
            seed = dlg.Invoke();
        }
        public static T ReadRecord(byte[] bytes, int offset, Dictionary<string, DbfColumn> columnDic)
        {
            return (T)(seed.ReadRecordFromBuffer(bytes, offset, columnDic));
        }
    }


    /// <summary>
    /// DBF记录单个字段属性
    /// </summary>
    [AttributeUsageAttribute(AttributeTargets.Field | AttributeTargets.Property)]
    public class DBFRecordFieldAttribute : Attribute
    {
        /// <summary>
        /// 记录内字段的偏移（记录内）
        /// </summary>
        public int Offset { get; private set; }

        /// <summary>
        /// 记录内字段的长度
        /// </summary>
        public int Length { get; private set; }

        /// <summary>
        /// 记录内字段的名称
        /// </summary>
        public string ColumnName { get; private set; }

        /// <summary>
        /// 构造器
        /// </summary>
        /// <param name="offset">记录内字段的偏移</param>
        /// <param name="length">记录内字段的长度</param>
        /// <param name="columnName">记录内字段的名称</param>
        public DBFRecordFieldAttribute(int offset, int length, string columnName)
        {
            this.Offset = offset;
            this.Length = length;
            this.ColumnName = columnName;
        }
    }
}
